package com.lsa.skienna.challenge.chap9.the110904_SlashMaze;

import java.awt.BasicStroke;
import java.awt.Button;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Scanner;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class SlashMazeRenderer {
	public static void main(String s[]) {
		JFrame frame = new JFrame();
		frame.setTitle("Slash maze");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		GridBagLayout gridBagLayout = new GridBagLayout();
		
		final SlashMazePanel slashMazePanel = new SlashMazePanel();
		GridBagConstraints cons = new GridBagConstraints();
		cons.gridx = 0;
        cons.gridy = 0;
		Button b = new Button("Export");
		b.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				BufferedImage bi = new BufferedImage(slashMazePanel.getSize().width, slashMazePanel.getSize().height, BufferedImage.TYPE_INT_ARGB); 
				Graphics g = bi.createGraphics();
				slashMazePanel.paint(g);  //this == JComponent
				g.dispose();
				try{ImageIO.write(bi,"png",new File("data/pc9/slashMaze/test.png"));}catch (Exception ee) {}
			}
		});
		frame.getContentPane().setLayout(gridBagLayout);
		frame.getContentPane().add(b, cons);
		cons = new GridBagConstraints();
        cons.fill = GridBagConstraints.BOTH;
        cons.gridx = 1;
        cons.gridy = 1;
        cons.weightx = 1;
        cons.weighty = 1;
		frame.getContentPane().add(new JScrollPane(slashMazePanel), cons);
		frame.pack();
		frame.setSize(new Dimension(800, 600));
		frame.setVisible(true);
	}
	
	static class SlashMazeModel {
		boolean[][] slashes;
		int w,h; 
		
		public boolean isEmpty() {
			return w < 1 || h < 1;
		}
		
		public void loadFromFile(String path) {
			try {
				Scanner sc = new Scanner(new FileInputStream(new File(path)));
				w = sc.nextInt();
				h = sc.nextInt();
				
				slashes = new boolean[w][h];
				
				if (w == 0 && h == 0) {
					return;
				}
				
				if (w == 0 || h == 0) {
					return;
				}
				
				for (int j = 0; j < h; j++) {
					String line = sc.next("[\\\\/]+");
					for (int i = 0; i < w; i++) {
						String token = line.substring(i, i + 1);
						if ("\\".equals(token)) {
							slashes[i][j] = false;
						}
						else if ("/".equals(token)) {
							slashes[i][j] = true;
						}
						else {
							throw new RuntimeException(String.format("unexpected token [%s]",token)); 
						}
					}
				}
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
		}
	}
	
	static class SlashMazePanel extends JPanel {
		SlashMazeModel model = new SlashMazeModel();
		boolean isEvenCell = false;
		
		public SlashMazePanel() {
			model.loadFromFile("data/pc9/slashMaze/110904.inp");
			setPreferredSize(new Dimension(640, 480));
		}
		
		public void paintComponent(Graphics g) {
			super.paintComponent(g);
			Graphics2D g2 = (Graphics2D) g;
			Dimension d = getSize();
			
			
			if (!model.isEmpty()) {
				int cellWidth = (int) (d.getWidth() /  model.w);
				int cellHeight = (int) (d.getHeight() /  model.h);
				
				for (int i = 0; i < model.w; i++) {
					for (int j = 0; j < model.h; j++) {
						int number = numberingFunction(i+1, j+1, model.w);
						int xStart = cellWidth*i;
						int yStart = cellHeight*j;
						int xEnd = cellWidth*(i+1);
						int yEnd = cellHeight*(j+1);
						
						if (model.slashes[i][j]) {
							drawSlash(g2, i,j, true, false, xStart, yStart, xEnd, yEnd);
						}
						else {
							drawSlash(g2, i,j, true, true, xStart, yStart, xEnd, yEnd);
						}
						
						if (!model.slashes[i][j]) {
							drawSlash(g2, i,j, false, false, xStart, yStart, xEnd, yEnd);
						}
						else {
							drawSlash(g2, i,j, false, true, xStart, yStart, xEnd, yEnd);
						}
						
						drawNodeNumber(g2, number, i, j, SIDE.NORTH, xStart,
								yStart, xEnd, yEnd);
						drawNodeNumber(g2, number + 1, i, j, SIDE.WEST, xStart,
								yStart, xEnd, yEnd);
						drawNodeNumber(g2, number + 2, i, j, SIDE.EAST, xStart,
								yStart, xEnd, yEnd);
						drawNodeNumber(g2, number + 3, i, j, SIDE.SOUTH,
								xStart, yStart, xEnd, yEnd);
						drawBox(g2, xStart, yStart, xEnd, yEnd);
					}
				}
			}
		}
		
		private enum SIDE{
			EAST,WEST,NORTH, SOUTH
		}
		
		private void drawNodeNumber(Graphics2D g2, int number, int j, int i, SIDE side, int xStart, int yStart, int xEnd, int yEnd) {
			int widthPart = (xEnd - xStart) / 4;
			int heightPart = (yEnd - yStart) / 4;
			
			g2.setFont(new Font("Arial", Font.BOLD, 11));
			g2.setColor(getNodeColor(i, j));
			
			switch (side) {
			case WEST:
				g2.drawString(""+number, xStart + widthPart, yStart + 2 * heightPart);
				break;
			case EAST:
				g2.drawString(""+number,  xEnd - widthPart, yStart + 2 * heightPart);
				break;
			case NORTH:
				g2.drawString(""+number,   xStart + 2 * widthPart, yStart + heightPart);
				break;
			case SOUTH:
				g2.drawString(""+number,   xStart + 2 * widthPart, yEnd - heightPart);
				break;
			}
		}
		
		private Color getNodeColor(int i, int j) {
			// 1 - 1 -> RED
			// 1 - 2 -> ORANGE
			// 2 - 1 -> ORANGE
			// 2 - 2 -> RED
			
			if ((i + j ) %2 == 0) {
				return Color.RED;
			}
			else {
				return Color.DARK_GRAY;
			}
		}
		
		private void drawSlash(Graphics2D g2, int i, int j, boolean isForward, boolean isDashed, int xStart, int yStart, int xEnd, int yEnd) {
			if (isDashed) {
				g2.setColor(Color.BLACK);
				g2.setStroke (new BasicStroke(
					      1f, 
					      BasicStroke.CAP_ROUND, 
					      BasicStroke.JOIN_ROUND, 
					      1f, 
					      new float[] {2f}, 
					      0f));
			}else {
				g2.setColor(getNodeColor(i, j));
				g2.setStroke (new BasicStroke(5.0f));
			}
			
			if (isForward) {
				g2.drawLine(xStart, yEnd, xEnd, yStart);
			}
			else {
				g2.drawLine(xStart, yStart, xEnd, yEnd);
			}
		}
		
		private void drawBox(Graphics2D g2,  int xStart, int yStart, int xEnd, int yEnd) {
			g2.setColor(Color.BLACK);
			g2.setStroke (new BasicStroke(
				      1f, 
				      BasicStroke.CAP_ROUND, 
				      BasicStroke.JOIN_ROUND, 
				      1f, 
				      new float[] {2f}, 
				      0f));
			
			g2.drawLine(xStart, yStart, xEnd, yStart);
			g2.drawLine(xEnd, yStart, xEnd, yEnd);
			g2.drawLine(xEnd, yEnd, xStart, yEnd);
			g2.drawLine(xStart, yEnd, xStart, yStart);
		}
		
		private static int numberingFunction(int i, int j, int w) {
			return 4 * i + 4 * w * j - 4 * w - 3;
		}
	}
}
